// 版权所有2011 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package math

/*
	Floating-point sine and cosine.
*/

// 下面的原始C代码、长注释和常量
// 来自http:
// 可从http:
// go代码是原始C.
// 
// sin的简化版本。c 
// 
// 循环正弦
// 
// 简介：
// 
// 双x，y，sin（）；
// y=sin（x）；
// 
// 说明：
// 
// 范围缩小为pi/4的区间。通过设计一种扩展精度的模运算，约化误差几乎被消除。
// 
// 使用了两个多项式逼近函数。
// 在0和pi/4之间，正弦近似为
// x+x**3p（x**2）。
// 在pi/4和pi/2之间，余弦表示为
// 1-x**2q（x**2）。
// 
// 准确度：
// 
// 相对误差：
// 算术域#试验峰值rms 
// DEC 0，10 150000 3.0e-17 7.8e-18 
// IEEE-1.07e9，+1.07e9 130000 2.1e-16 5.4e-17 
// 
// 在x=2**30=1.074e9时开始出现部分精度损失。
// 的损失不是渐进的，而是突然跳到10e7的1分左右。对于x>2**49=5.6e14，结果可能毫无意义。
// 
// cos。c 
// 
// 圆余弦
// 
// 简介：
// 
// 双x，y，cos（）；
// y=cos（x）；
// 
// 说明：
// 
// 范围缩小为pi/4的区间。通过设计一种扩展精度的模运算，约化误差几乎被消除。
// 
// 使用了两个多项式逼近函数。
// 在0和pi/4之间，余弦近似为
// 1-x**2q（x**2）。在pi/4和pi/2之间，正弦表示为x+x**3p（x**2）。
// 
// 准确度：
// 
// 相对误差：
// 算术域#试验峰值均方根
// IEEE-1.07e9，+1.07e9 130000 2.1e-16 5.4e-17 
// 
// Cephes数学库发行版2.8:2000年6月
// 版权所有1984、1987、1989、1992、2000作者Stephen L.Moshier 
// 
// http:
// 本档案中的一些软件可能来自《数学函数的方法和程序》（Prentice Hall或Simon&Schuster 
// International，1989）一书，也可能来自Cephes数学图书馆，一本
// 商业产品。无论哪种情况，它都是作者的版权。
// 您在这里看到的内容可以免费使用，但没有任何支持或
// 保证。
// 
// 本书中两个已知的印刷错误在这里的
// 伽马函数和不完整的beta 
// 积分的源代码列表中修复。
// 
// Stephen L.Moshier 
// moshier@na-网。奥尔。gov 

// sin系数
var _sin = [...]float64{
	1.58962301576546568060e-10, // 0x3de5d8fd1fd19ccd 
	-2.50507477628578072866e-8, // 0xbe5ae5e5a9291f5d 
	2.75573136213857245213e-6,  // 0x3ec71de3567d48a1 
	-1.98412698295895385996e-4, // 0xBF2A001A019BFDF03 
	8.33333333332211858878e-3,  // 0x3f8111111110f7d0 
	-1.66666666666666307295e-1, // 0xBFC55555555548 
}

var _cos = [...]float64{
	-2.75573141792967388112e-7,  // 0xbe927e4f7eac4bc6 
	2.48015872888517045348e-5,   // 0x3EFA001A019C844F5 
	-1.38888888888730564116e-3,  // 0xbf56c16c16c14f91 
	4.16666666666665929218e-2,   // 0x3fa555555555554b 
}

// Cos返回弧度参数x的余弦。
func Cos(x float64) float64 {
	if haveArchCos {
		return archCos(x)
	}
	return cos(x)
}

func cos(x float64) float64 {
	const (
		PI4B = 3.77489470793079817668e-8  // 0x3E6444D00000000，
		PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170，
	)
	// 特殊情况
	switch {
	case IsNaN(x) || IsInf(x, 0):
		return NaN()
	}

	// 使参数为正
	sign := false
	x = Abs(x)

	var j uint64
	var y, z float64
	if x >= reduceThreshold {
		j, z = trigReduce(x)
	} else {
		j = uint64(x * (4 / Pi)) // x的整数部分/（Pi/4），作为相位角测试的整数
		y = float64(j)           // x的整数部分/（Pi/4），as float 

		// 将零映射到原点
		if j&1 == 1 {
			j++
			y++
		}
		j &= 7                               // 八分之一模2Pi弧度（360度）
		z = ((x - y*PI4A) - y*PI4B) - y*PI4C // 扩展精度模运算
	}

	if j > 3 {
		j -= 4
		sign = !sign
	}
	if j > 1 {
		sign = !sign
	}

	zz := z * z
	if j == 1 || j == 2 {
		y = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
	} else {
		y = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5])
	}
	if sign {
		y = -y
	}
	return y
}

// Sin返回弧度参数x的正弦。
// 
// 特殊情况为：
// Sin（±Inf）=NaN 
func Sin(x float64) float64 {
	if haveArchSin {
		return archSin(x)
	}
	return sin(x)
}

func sin(x float64) float64 {
	const (
		PI4A = 7.85398125648498535156e-1  // 0x3FE921FB4000000，Pi/4分为三部分
		PI4B = 3.77489470793079817668e-8  // 0x3E6444D00000000，
		PI4C = 2.69515142907905952645e-15 // 0x3ce8469898cc5170，
	)
	// 特殊情况
	switch {
	case x == 0 || IsNaN(x):
		return x // 返回±0 | | NaN（）
	case IsInf(x, 0):
		return NaN()
	}

	// 使参数为正，但保存符号
	sign := false
	if x < 0 {
		x = -x
		sign = true
	}

	var j uint64
	var y, z float64
	if x >= reduceThreshold {
		j, z = trigReduce(x)
	} else {
		y = float64(j)           // x/（Pi/4）的整数部分，作为浮点

		// 将零映射到原点
		if j&1 == 1 {
			j++
			y++
		}
		j &= 7                               // 八分之一模2Pi弧度（360度）
		z = ((x - y*PI4A) - y*PI4B) - y*PI4C // 扩展精度模运算
	}
	// 在x轴上反射
	if j > 3 {
		sign = !sign
		j -= 4
	}
	zz := z * z
	if j == 1 || j == 2 {
		y = 1.0 - 0.5*zz + zz*zz*((((((_cos[0]*zz)+_cos[1])*zz+_cos[2])*zz+_cos[3])*zz+_cos[4])*zz+_cos[5])
	} else {
		y = z + z*zz*((((((_sin[0]*zz)+_sin[1])*zz+_sin[2])*zz+_sin[3])*zz+_sin[4])*zz+_sin[5])
	}
	if sign {
		y = -y
	}
	return y
}
